package Java8新特性;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/*
    Stream 的终止操作
         终止操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如:List、Integer甚至是 void
         流进行了终止操作后,不能再次使用

     匹配与查找
        allMatch(Predicate p):检查是否匹配所有元素
        anyMatch(Predicate p):检查是否至少匹配一个元素
        noneMatch(Predicate p):检查是否没有匹配所有元素
        findFirst():返回第一个元素
        findAny():返回当前流中的任意元素
        count():返回流中元素总数
        max(Comparator c):返回流中最大值
        min(Comparator c):返回流中最小值
        forEach(Consumer c):内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代,相反,Stream API 使用内部迭代——帮用户完成迭代操作)

     归约
        reduce(T iden, BinaryOperator b):可以将流中元素反复结合起来,得到一个值,返回 T
        reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值,返回 Optional<T>

     收集
        collect(Collector c):将流转换为其他形式,接收一个 Collector 接口的实现,用于给Stream中元素做汇总的方法

        Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map),在Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下:
             toList                  List<T>               把流中元素收集到List
             toSet                   Set<T>                把流中元素收集到Set
             toCollection            Collection<T>         把流中元素收集到创建的集合
             counting                Long                  计算流中元素的个数
             summingInt              Integer               对流中元素的整数属性求和
             averagingInt            Double                计算流中元素Integer属性的平均值
             summarizingInt          IntSummaryStatistics  收集流中Integer属性的统计值,如:平均值
             joining                 String                连接流中每个字符串
             maxBy                   Optional<T>           根据比较器选择最大值
             minBy                   Optional<T>           根据比较器选择最小值
             reducing                归约产生的类型           从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
             collectingAndThen       转换函数返回的类型        包裹另一个收集器,对其结果转换函数
             groupingBy              Map<K, List<T>>       根据某属性值对流分组,属性为K,结果为V
             partitioningBy          Map<Boolean, List<T>> 根据true或false进行分区
 */
public class StreamAPI07 {

    //匹配与查找
    @Test
    public void test1(){
        List<Employee> list = EmployeeData.getEmployees();

        //allMatch(Predicate p):检查是否匹配所有元素
        boolean allMatch = list.stream().allMatch(e -> e.getAge() > 18); //判定所有员工的年龄是否都大于18岁
        System.out.println(allMatch);

        //anyMatch(Predicate p):检查是否至少匹配一个元素
        boolean anyMatch = list.stream().anyMatch(e -> e.getSalary() > 10000); //是否存在员工的工资大于10000
        System.out.println(anyMatch);

        //noneMatch(Predicate p):检查是否没有匹配所有元素
        boolean noneMatch = list.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(noneMatch);

        //findFirst():返回第一个元素
        Optional<Employee> first = list.stream().findFirst();
        System.out.println(first);

        //findAny():返回当前流中的任意元素
        Optional<Employee> any = list.stream().findAny();
        System.out.println(any);

        //count():返回流中元素总数
        long count = list.stream().filter(e -> e.getSalary() > 5000).count();
        System.out.println(count);

        //max(Comparator c):返回流中最大值
        Optional<Double> max = list.stream().map(e -> e.getSalary()).max(Double::compare); //返回最高的工资
        System.out.println(max);

        //min(Comparator c):返回流中最小值
        Optional<Employee> min = list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())); //返回工资最低的员工信息
        System.out.println(min);

        //forEach(Consumer c):内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代,相反,Stream API 使用内部迭代——帮用户完成迭代操作)
        list.stream().forEach(System.out::println);

        //使用集合的遍历操作
        list.forEach(System.out::println);
    }

    //归约
    @Test
    public void test2(){
        /*
            reduce(T iden, BinaryOperator b):可以将流中元素反复结合起来,得到一个值,返回 T
                reduce 接受2个参数:
                    1、初始值
                    2、BinaryOperator<T>来将两个元素结合起来产生一个新值
         */
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer reduce = list.stream().reduce(0, Integer::sum);  //第一个参数为初始值
        System.out.println(reduce);

        /**
         * reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值,返回 Optional<T>
         *   它不接受初始值,但是会返回一个Optional对象:
         *       考虑流中没有任何元素的情况,reduce操作无法返回其和,因为它没有初始值,这就是为什么结果被包裹在一个Optional对象里,以表明和可能不存在
         */
        List<Employee> eList = EmployeeData.getEmployees();
        Optional<Double> sumMoney = eList.stream().map(Employee::getSalary).reduce(Double::sum);
        //Optional<Double> sumMoney = eList.stream().map(Employee::getSalary).reduce((d1,d2) -> d1 + d2);  另一种写法
        System.out.println(sumMoney);
    }

    //收集
    @Test
    public void test3(){
        //collect(Collector c):将流转换为其他形式,接收一个 Collector 接口的实现,用于给Stream中元素做汇总的方法
        List<Employee> list = EmployeeData.getEmployees();

        //查找工资大于6000的员工,其结果返回一个List
        List<Employee> collect = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        collect.forEach(System.out::println);

        //查找工资大于6000的员工,其结果返回一个Set
        Set<Employee> set = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        set.forEach(System.out::println);
    }
}
